package com.cxyzy.demo;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 文件操作类
 */
public class FileUtils {


    /**
     * 拼接2个文件
     * @param srcFile
     * @param offset
     * @param dstFile
     * @throws IOException
     */
    public static void concat(String srcFile, long offset, String dstFile)
            throws IOException {
        concat(new File(srcFile), offset, new File(dstFile));
    }

    
    /**
     * 拼接2个文件
     * @param srcFile
     * @param offset
     * @throws IOException
     */
    private static void concat(File srcFile, long offset, File destFile)
            throws IOException {
        final long CHUNK_SIZE = 4 * 1024;

        if (destFile.exists() && destFile.isDirectory()) {
            throw new IOException("Destination '" + destFile
                    + "' exists but is a directory");
        }

        RandomAccessFile rif = new RandomAccessFile(srcFile, "r");
        FileOutputStream fos = null;
        FileChannel input = null;
        FileChannel output = null;
        try {
            long pos = 0;
            long size = rif.length();
            long count = 0;

            if (offset > size) {
                return;
            }
            rif.seek(offset);
            pos = offset;

            fos = new FileOutputStream(destFile, true);
            input = rif.getChannel();
            output = fos.getChannel();

            while (pos < size) {
                count = (size - pos) > CHUNK_SIZE ? CHUNK_SIZE : (size - pos);
                pos += output.transferFrom(input, pos, count);
            }
        } finally {
            if (output != null) {
                output.force(true);
                output.close();
            }
            if (fos != null) {
                fos.flush();
                fos.close();
            }
            if (input != null) {
                input.close();
            }
            if (rif != null) {
                rif.close();
            }
        }
    }

    /**
     * 保存流到指定路径
     * @param inputStream
     * @param dst
     * @throws IOException
     */
    public static void save(InputStream inputStream, String dst)
            throws IOException {
        File f = new File(dst);

        if (!f.exists()) {
            f.createNewFile();
            // f.delete();
        }

        OutputStream outputStream = new BufferedOutputStream(
                new FileOutputStream(f));

        byte[] buffer = new byte[1024];
        int readIndex;
        while (-1 != (readIndex = inputStream.read(buffer, 0, buffer.length))) {
            outputStream.write(buffer, 0, readIndex);
        }

        outputStream.flush();
        inputStream.close();
        outputStream.close();
    }

    public static final long GB = 1073741824; // 1024 * 1024 * 1024
    public static final long MB = 1048576; // 1024 * 1024
    public static final long KB = 1024;

    public static final int ICON_TYPE_ROOT = 1;
    public static final int ICON_TYPE_FOLDER = 2;
    public static final int ICON_TYPE_MP3 = 3;
    public static final int ICON_TYPE_MTV = 4;
    public static final int ICON_TYPE_JPG = 5;
    public static final int ICON_TYPE_FILE = 6;

    public static final String MTV_REG = "^.*\\.(mp4|3gp)$";
    public static final String MP3_REG = "^.*\\.(mp3|wav)$";
    public static final String JPG_REG = "^.*\\.(gif|jpg|png)$";

    private static final String FILENAME_REGIX = "^[^\\/?\"*:<>\\]{1,255}$";

    /**
     * 递归删除文件和文件夹
     *
     * @param file 要删除的根目录
     * @return {@code true} if this file was deleted, {@code false} otherwise.
     */
    public static boolean DeleteFile(File file) {
        if (file == null || !file.exists()) {
            return false;
        }
        if (file.isFile()) {
            return file.delete();
        }
        if (!file.isDirectory()) {
            return false;
        }
        File[] childFile = file.listFiles();
        if (childFile == null || childFile.length == 0) {
            return file.delete();
        }
        for (File f : childFile) {
            DeleteFile(f);
        }
        return file.delete();
    }

    /**
     * 重命名文件和文件夹
     *
     * @param file        File对象
     * @param newFileName 新的文件名
     * @return 执行结果
     */
    public static boolean renameFile(File file, String newFileName) {
        if (newFileName.matches(FILENAME_REGIX)) {
            File newFile = null;
            if (file.isDirectory()) {
                newFile = new File(file.getParentFile(), newFileName);
            } else {
                String temp = newFileName
                        + file.getName().substring(
                        file.getName().lastIndexOf('.'));
                newFile = new File(file.getParentFile(), temp);
            }
            if (file.renameTo(newFile)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 关闭流
     * @param closeable
     */
    public static void closeQuietly(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取文件字节数，获取失败返回-1
     * @param file
     * @return
     */
    public static long getFileBytesSize(File file) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            int length = fis.available();
            return length;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeQuietly(fis);
        }
        return -1;
    }

    /**
     * 文件大小获取
     *
     * @param file File对象
     * @return 文件大小字符串
     */
    public static String getFileSize(File file) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            int length = fis.available();
            if (length >= GB) {
                return String.format("%.2f GB", length * 1.0 / GB);
            } else if (length >= MB) {
                return String.format("%.2f MB", length * 1.0 / MB);
            } else {
                return String.format("%.2f KB", length * 1.0 / KB);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "未知";
    }

    /**
     * 使用系统程序打开文件
     *
     * @param activity Activity
     * @param file     File
     * @throws Exception
     */
    public static void openFile(Activity activity, File file) throws Exception {
        Intent intent = new Intent();
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file), getMimeType(file, activity));
        activity.startActivity(intent);
    }

    /**
     * 获取以后缀名为ID的值
     *
     * @param file     File
     * @param activity Activity
     * @return MimeType字符串
     * @throws Exception 未知格式抛出此异常
     */
    public static String getMimeType(File file, Activity activity) throws Exception {

        String name = file.getName()
                .substring(file.getName().lastIndexOf('.') + 1).toLowerCase();
        int id = activity.getResources().getIdentifier(
                activity.getPackageName() + ":string/" + name, null, null);

        // 特殊处理
        if ("class".equals(name)) {
            return "application/octet-stream";
        }
        if ("3gp".equals(name)) {
            return "video/3gpp";
        }
        if ("nokia-op-logo".equals(name)) {
            return "image/vnd.nok-oplogo-color";
        }
        if (id == 0) {
            throw new Exception("未找到分享该格式的应用");
        }
        return activity.getString(id);
    }

    /**
     * 用于递归查找文件夹下面的符合条件的文件
     *
     * @param folder 文件夹
     * @param filter 文件过滤器
     * @return 符合条件的文件List
     */
    public static List<HashMap<String, Object>> recursionFolder(File folder, FileFilter filter) {

        List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();

        // 获得文件夹下的所有目录和文件集合
        File[] files = folder.listFiles();
        /** 如果文件夹下没内容,会返回一个null **/
        // 判断适配器是否为空
        if (filter != null) {
            files = folder.listFiles(filter);
        }
        // 找到合适的文件返回
        if (files != null) {
            for (int m = 0; m < files.length; m++) {
                File file = files[m];
                if (file.isDirectory()) {
                    // 是否递归调用
                    list.addAll(recursionFolder(file, filter));

                } else {
                    HashMap<String, Object> map = new HashMap<String, Object>();
                    map.put("file", file);
                    // 设置图标种类
                    if (file.getAbsolutePath().toLowerCase().matches(MP3_REG)) {
                        map.put("iconType", 3);
                    } else if (file.getAbsolutePath().toLowerCase()
                            .matches(MTV_REG)) {
                        map.put("iconType", 4);
                    } else if (file.getAbsolutePath().toLowerCase()
                            .matches(JPG_REG)) {
                        map.put("iconType", 5);
                    } else {
                        map.put("iconType", 6);
                    }
                    list.add(map);
                }
            }
        }
        return list;
    }

    /**
     * 资源管理器,查找该文件夹下的文件和目录
     *
     * @param folder 文件夹
     * @param filter 文件过滤器
     * @return 符合条件的List
     */
    public static List<HashMap<String, Object>> unrecursionFolder(File folder,
                                                                  FileFilter filter) {
        List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
        // 如果是SD卡路径,不添加父路径
        if (!folder.getAbsolutePath().equals(
                Environment.getExternalStorageDirectory().getAbsolutePath())) {
            HashMap<String, Object> map = new HashMap<String, Object>();
            map.put("file", folder.getParentFile());
            map.put("iconType", ICON_TYPE_ROOT);
            list.add(map);
        }
        // 获得文件夹下的所有目录和文件集合
        File[] files = folder.listFiles();
        /** 如果文件夹下没内容,会返回一个null **/
        // 判断适配器是否为空
        if (filter != null) {
            files = folder.listFiles(filter);
        }
        if (files != null && files.length > 0) {
            for (File p : files) {
                HashMap<String, Object> map = new HashMap<String, Object>();
                map.put("file", p);
                // 设置图标种类
                if (p.isDirectory()) {
                    map.put("iconType", ICON_TYPE_FOLDER);
                } else {
                    if (p.getAbsolutePath().toLowerCase().matches(MP3_REG)) {
                        map.put("iconType", ICON_TYPE_MP3);
                    } else if (p.getAbsolutePath().toLowerCase()
                            .matches(MTV_REG)) {
                        map.put("iconType", ICON_TYPE_MTV);
                    } else if (p.getAbsolutePath().toLowerCase()
                            .matches(JPG_REG)) {
                        map.put("iconType", ICON_TYPE_JPG);
                    } else {
                        map.put("iconType", ICON_TYPE_FILE);
                    }
                }
                // 添加
                list.add(map);
            }
        }
        return list;
    }

    /**
     * 示例:"^.*\\.(mp3|mp4|3gp)$"
     *
     * @param reg 目前允许取值 REG_MTV, REG_MP3, REG_JPG三种
     * @return 文件过滤器
     */
    public static FileFilter getFileFilter(final String reg, boolean isdir) {
        if (isdir) {
            return new FileFilter() {
                @Override
                public boolean accept(File pathname) {

                    return pathname.getAbsolutePath().toLowerCase()
                            .matches(reg)
                            || pathname.isDirectory();
                }
            };
        } else {
            return new FileFilter() {
                @Override
                public boolean accept(File pathname) {

                    return pathname.getAbsolutePath().toLowerCase()
                            .matches(reg)
                            && pathname.isFile();
                }
            };
        }
    }

    public final static String FILE_EXTENSION_SEPARATOR = "";

    /**
     * 输入流转byte[]
     *
     * @param inStream InputStream
     * @return Byte数组
     */
    public static byte[] input2byte(InputStream inStream) {
        if (inStream == null)
            return null;
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        try {
            while ((rc = inStream.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return swapStream.toByteArray();
    }

    /**
     * 获取文件名，去掉后缀
     * <p/>
     * <pre>
     *      getFileNameWithoutExtension(null)               =   null
     *      getFileNameWithoutExtension("")                 =   ""
     *      getFileNameWithoutExtension("   ")              =   "   "
     *      getFileNameWithoutExtension("abc")              =   "abc"
     *      getFileNameWithoutExtension("a.mp3")            =   "a"
     *      getFileNameWithoutExtension("a.b.rmvb")         =   "a.b"
     *      getFileNameWithoutExtension("c:\\")              =   ""
     *      getFileNameWithoutExtension("c:\\a")             =   "a"
     *      getFileNameWithoutExtension("c:\\a.b")           =   "a"
     *      getFileNameWithoutExtension("c:a.txt\\a")        =   "a"
     *      getFileNameWithoutExtension("/home/admin")      =   "admin"
     *      getFileNameWithoutExtension("/home/admin/a.txt/b.mp3")  =   "b"
     * </pre>
     *
     * @param filePath 文件路径
     * @return file name from path, not include suffix
     * @see
     */
    public static String getFileNameWithoutExtension(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return filePath;
        }

        int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);
        int filePosi = filePath.lastIndexOf(File.separator);
        if (filePosi == -1) {
            return (extenPosi == -1 ? filePath : filePath.substring(0,
                    extenPosi));
        }
        if (extenPosi == -1) {
            return filePath.substring(filePosi + 1);
        }
        return (filePosi < extenPosi ? filePath.substring(filePosi + 1,
                extenPosi) : filePath.substring(filePosi + 1));
    }

    /**
     * 获取文件扩展名
     * <p/>
     * <pre>
     *      getFileExtension(null)               =   ""
     *      getFileExtension("")                 =   ""
     *      getFileExtension("   ")              =   "   "
     *      getFileExtension("a.mp3")            =   "mp3"
     *      getFileExtension("a.b.rmvb")         =   "rmvb"
     *      getFileExtension("abc")              =   ""
     *      getFileExtension("c:\\")              =   ""
     *      getFileExtension("c:\\a")             =   ""
     *      getFileExtension("c:\\a.b")           =   "b"
     *      getFileExtension("c:a.txt\\a")        =   ""
     *      getFileExtension("/home/admin")      =   ""
     *      getFileExtension("/home/admin/a.txt/b")  =   ""
     *      getFileExtension("/home/admin/a.txt/b.mp3")  =   "mp3"
     * </pre>
     *
     * @param filePath 文件路径
     * @return
     */
    public static String getFileExtension(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return filePath;
        }

        int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);
        int filePosi = filePath.lastIndexOf(File.separator);
        if (extenPosi == -1) {
            return "";
        }
        return (filePosi >= extenPosi) ? "" : filePath.substring(extenPosi + 1);
    }


    /**
     * 文件是否存在
     *
     * @param filePath 文件路径
     * @return 是否存在文件
     */
    public static boolean isFileExist(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return false;
        }

        File file = new File(filePath);
        return (file.exists() && file.isFile());
    }

    /**
     * 文件夹是否存在
     *
     * @param directoryPath 文件夹路径
     * @return 文件夹是否存在
     */
    public static boolean isFolderExist(String directoryPath) {
        if (TextUtils.isEmpty(directoryPath)) {
            return false;
        }

        File dire = new File(directoryPath);
        return (dire.exists() && dire.isDirectory());
    }

    /**
     * 删除文件或文件夹,会递归删除子文件夹的文件。
     * <ul>
     * <li>if path is null or empty, return true</li>
     * <li>if path not exist, return true</li>
     * <li>if path exist, delete recursion. return true</li>
     * <ul>
     *
     * @param path 文件路径
     * @return 是否删除成功
     */
    public static synchronized boolean deleteFile(String path) {
        if (TextUtils.isEmpty(path)) {
            return true;
        }

        File file = new File(path);
        if (!file.exists()) {
            return true;
        }
        if (file.isFile()) {
            return file.delete();
        }
        if (!file.isDirectory()) {
            return false;
        }
        File[] subFiles = file.listFiles();
        if (subFiles != null){
            for (File f : subFiles) {
                if (f.isFile()) {
                    f.delete();
                } else if (f.isDirectory()) {
                    deleteFile(f.getAbsolutePath());
                }
            }
        }
        return file.delete();
    }

    /**
     * 拷贝文件
     *
     * @param s 源文件
     * @param t 目标文件
     */
    public static void copyFile(File s, File t) {
        FileInputStream fi = null;
        FileOutputStream fo = null;
        FileChannel in = null;
        FileChannel out = null;

        try {
            if (! t.exists())
            {
                t.createNewFile();
            }

            fi = new FileInputStream(s);
            fo = new FileOutputStream(t);
            in = fi.getChannel();
            out = fo.getChannel();
            // 连接两个通道，并且从in通道读取，然后写入out通道
            in.transferTo(0, in.size(), out);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeQuietly(fo);
            closeQuietly(fi);
            closeQuietly(in);
            closeQuietly(out);
        }
    }

    /**
     * 判断文件是否存在
     * @param file
     * @return
     */
    public static boolean isFileExists(String file) {
        try {
            File f = new File(file);
            if (!f.exists()) {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据文件路径 递归创建文件
     *
     * @param file
     */
    public static void createDipPath(String file) {
        String parentFile = file.substring(0, file.lastIndexOf("/"));
        File file1 = new File(file);
        File parent = new File(parentFile);
        if (!file1.exists()) {
            boolean mkdirs = parent.mkdirs();
            try {
                if(mkdirs) {
                    boolean newFile = file1.createNewFile();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
